/*
 *  World.h
 *  GLRender
 *
 *  Created by Patrick zulian on 5/4/10.
 *  Copyright 2010 University  of Lugano. All rights reserved.
 *
 */

#ifndef WORLD_H
#define WORLD_H

#include "Base.h"
#include "WMovingObject.h"
#include "Globals.h"
#include "Player.h"
#include <vector>
#include "AbstractRenderer.h"
#include "SoundEngine.h"
#include <QString>
#include "CollisionSystem.h"
#include "WLevel.h"
#include "Explosion.h"
#include "ParticleSystem.h"
#include "Fragmentation.h"

class World  {
private:
	typedef std::vector<WObject *>::iterator WObjIt;
	typedef std::vector<WMovingObject *>::iterator WMvObjIt;
	std::vector<WObject *> wObjects;
	std::vector<WMovingObject *> wMvObjects;
	std::vector<Explosion> explosions;
	std::vector<Fragmentation> fragmentations;
	double lastCollisionCheck, timeElapsed, collisionCheckFreq;
	
	Player * player;
	Level *  currentLevel;
	
	bool debugInsideCollisionZone, pause, newExplosion, playerHit, bigExplosion;
	
	CollisionSystem *collSys;
	
	ParticleSystem *particleSystem;
	
	void init();
	void eraseDeadObjects();
	void clear();
	
	inline
	bool hasToCheckCollision(const double tau) { return timeElapsed - lastCollisionCheck  > tau * collisionCheckFreq;  }
	
	inline 
	void scheduleColllision(const double tau ) { if(hasToCheckCollision(tau)) { lastCollisionCheck = timeElapsed; } }
	
	void setLevel(Level * l);
	void goToFirstLevel();
	void goToNextLevel();
	void checkBonus (WObject *o);
	void addExplosion(WObject * o);
	void addFragmentation(WObject * o);
public:
	
	World();
	
	virtual
	~World() { }
	void step(const double tau);
	
	void renderOn(AbstractRenderer * renderer);
	
	Player * getPlayer()
	{
		return player;
	}
	
	void setPlayer(Player * player)
	{
		this->player = player;
		this->player->setObjective(currentLevel->getObjective());
	}
	
	void addSlowObject (WMovingObject *w);
	void addFastObject (WMovingObject *w);
	
	void onGameStarted();
	
	inline 
	const unsigned int getNumberOfEnemies() const{ return wObjects.size(); }
	
	inline
	const double getTimeElapsed () const { return this->timeElapsed; }
	
	inline const bool isPause() const {return pause;}
	
	void togglePause();

	inline
	bool inFront(const Point3d &position) { 
		Point3d dirToPos = position - player->position(), playerDir = player->velocity(); 
		dirToPos.normalize(); playerDir.normalize();
		return dirToPos * playerDir > 0;
	}
	
};


#endif
